using AnalyStock.DataAnalysis;
using AnalyStock.DataManage;

namespace AnalyStock.GrapImage;

/// <summary>
///     加载基础数据集合：KlineData(用于传递给画K图等方法),StockInfo（当前股票基础资料）
/// </summary>
/// <returns></returns>
public partial class ChartKline : UserControl
{
    private KlineData currKlinedata;

    //默认填充蜡烛数据为日数据，改变期间类型：周数据、月数据
    private CandlePointSet.PeriodType currPeriodType = default;
    private StockInfo currStockInfo;

    //如果选择股票变更，设定标志，K线所需数据全部要重新提取，否则只刷新变化数据
    private bool IsStockChanged;

    //外部调用时，是否等待全部股票信息填充完毕
    internal bool IsWaitFillStockInfos = true;

    //当外部需要调用 AllStockInfos数据时，加载完成后触发事件，避免接受的数据集为NULL。
    internal event EventHandler<IList<StockInfo>> StockInfosFilled;
    protected void OnStockInfosFilled(IList<StockInfo> stocks) =>
        StockInfosFilled?.Invoke(this, stocks);
    //当外部需要调用自选股集合数据时，加载完成后触发事件，避免接受的数据集为NULL。
    internal event EventHandler<(IList<SelectStock>, IList<Conception>)> SeleStocksFilled;
    protected void OnSeleStocksFilled((IList<SelectStock>, IList<Conception>) selectStocks) =>
        SeleStocksFilled?.Invoke(this, selectStocks);

    //K线所需数据加载完毕后触发,开始Kline的各种组件画画
    private event EventHandler<KlineData> KlineDataFilled;
    protected void OnKlineDataFilled(KlineData data) =>
        KlineDataFilled?.Invoke(this, data);
    /// <summary>
    ///     改变当前股票信息
    /// </summary>
    /// <param name="stockCode"></param>
    public void ChangeCurrentStock(string stockCode, string conception = default)
    {
        if (stockCode is null)
        {
            currStockInfo.Conception = string.Empty;
            currStockInfo.Note = string.Empty;
            currStockInfo.IsSele = false;
            return;
        }
        currStockInfo = FillCurrentStockInfo(stockCode, conception);
        if (currStockInfo is not null)
        {
            ChangeKlineData(DaysChangeType.IniDays);
        }
    }

    public void ChangeCurrentStock(StockInfo stockInfo)
    {
        if (stockInfo is null) { return; }
        currStockInfo = stockInfo;
        ChangeKlineData(DaysChangeType.IniDays);
    }

    /// <summary>
    ///     获取全部股票基础信息
    /// </summary>
    /// <returns></returns>
    public static IList<StockInfo> GetAllStockInfos()
    {
        return StockInfos ?? new List<StockInfo>();
    }

    /// <summary>
    ///     获取当前股票基础信息
    /// </summary>
    /// <returns></returns>
    public StockInfo GetCurrentStockInfo()
    {
        return currStockInfo ?? new();
    }
    public static IList<SelectStock> GetSelectStocks()
    {
        return SelectStocks ?? new List<SelectStock>();
    }

    /// <summary>
    ///     刷新K线作图数据，根据K线的数据期间类型：日线、周线、月线
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private void ChangeKlineData(DaysChangeType type)
    {
        if (!isLockQueryDate)
        {
            ChangeQueryDates(type);
        }
        IsStockChanged =
            !(currStockInfo.Ts_code == currKlinedata?.StockInfo.Ts_code);
        FillKlineDataAsync().WithCapturaException();
    }

    /// <summary>
    ///     加载分钟线数据、蜡烛线历史数据和财务数据，完成后触发数据加载完成事件
    /// </summary>
    /// <returns></returns>
    private async Task FillKlineDataAsync()
    {
        currKlinedata ??= new KlineData();
        if (IsStockChanged)
        {
            currKlinedata.Dispose();
            currKlinedata.StockInfo = currStockInfo;
        }

        //加载分钟数据
        var _minutedatas = await FillMinuteDatasAsync();
        if (!_minutedatas.IsNullOrEmpty())
        {
            currKlinedata.MinuteDatas = _minutedatas;
        }

        //加载日交易数据，若分钟数据变化，追加分钟数据为当日交易数据
        currKlinedata.Dailies = await FillDailesAsync();
        //加载财务指标      
        var _financials = await FillFinanIndexsAsync();
        if (!_financials.IsNullOrEmpty())
        {
            currKlinedata.Financials = _financials;
        }

        /* 数据加载完成后，传递K线数据，执行后续操作；加载的数据通过委托事件进行传递
        此处使用委托在逻辑上是为了区分了数据加载过程和后续如画图等动作过程。*/
        OnKlineDataFilled(currKlinedata);

    }

    //获得在线分时线数据;只有股票代码变更才能重新获取在线
    private async Task<IList<MinuteData>> FillMinuteDatasAsync()
    {
        //如果面板隐藏，则不下载数据，返回空值
        if (!IsMinutePanelVisible)
        {
            return null;
        }
        //如果股票改变，或者分钟数据集为空，则重新下载数据集
        if (IsStockChanged || currKlinedata.MinuteDatas.IsNullOrEmpty())
        {//网易接口分时线接口            
            return await currStockInfo.Ts_code.GetMinuteDataOnTencentAsync();
        }
        return null;
    }

    private async Task<DailyOfTencent> FillCurrentDailyAsync(string stockCode)
    {
        return await DownLoadExtensions_Tencent.GetCurrentDailyOnTencentAsync(stockCode);
    }

    /// <summary>
    ///     加载历史交易数据、当日分钟线形成的交易数据
    /// </summary>
    /// <param name="minuteDatas"></param>
    /// <returns></returns>
    private async Task<IList<Daily>> FillDailesAsync()
    {
        var _dailes = await CommDataMethod<Daily>
            .GetDataOnlineOrDbsetAsync(CheckBInline.IsChecked.Value,
                currStockInfo.Ts_code,
                startDate,
                endDate);
        _dailes?.AddCurrentDailyByMinute(currKlinedata.MinuteDatas);
        return _dailes;
    }

    //加载财务指标数据
    private async Task<IList<DynamicFinancialIndex>> FillFinanIndexsAsync()
    {
        if (!IsStockChanged)
        {
            return null;
        }
        return await CommDataMethod<DynamicFinancialIndex>
                .GetDataOnlineOrDbsetAsync(CheckBFinaceInline.IsChecked.Value,
                                        currStockInfo.Ts_code,
                                        $"{DateTime.Today.Year - 3}0101",
                                        DateTime.Today.ToDateString());
    }

    /// <summary>
    /// 加载股票基础信息
    /// </summary>
    /// <param name="stockCode"></param>
    /// <param name="conception"></param>
    /// <returns></returns>
    private static StockInfo FillCurrentStockInfo(string stockCode, string conception = default)
    {
        var _stockInfo = StockInfos?.FirstOrDefault(n => n.Ts_code == stockCode);
        if (_stockInfo is null) return _stockInfo;
        //填充“概念分类”
        var _seleStock = SelectStocks?.FirstOrDefault(n => n.Ts_code == stockCode
                                    && n.Conception == conception);
        if (_seleStock is not null)
        {
            _stockInfo.Conception = _seleStock.Conception;
            _stockInfo.IsSele = true;
        }
        //填充“股票备注”
        var _stockNote = StockNotes?.FirstOrDefault(n => n.Ts_code == stockCode);
        if (_stockNote is not null)
        {
            _stockInfo.Note = _stockNote.Note;
        }
        return _stockInfo;
    }


    /// <summary>
    ///     加载股票的所有备份信息
    /// </summary>
    /// <returns></returns>
    private void FillStockInfos()
    {
        FillStockInfosAsync().WithCapturaException();
    }
    private async Task FillStockInfosAsync()
    {
        await Task.Delay(5);
        StockInfos ??= await FillDataAsync<StockInfo>();
        SelectStocks ??= await FillDataAsync<SelectStock>();
        Conceptions ??= await FillDataAsync<Conception>();
        StockNotes ??= await FillDataAsync<StockNote>();
        if (IsWaitFillStockInfos)
        {
            OnStockInfosFilled(StockInfos);
            OnSeleStocksFilled((SelectStocks, Conceptions));
        }

        static async Task<IList<T>> FillDataAsync<T>() where T : class, new()
        {
            return await CommDataMethod<T>.GetDataOnDbSetAsync();
        }
    }

    private static async Task<IList<Conception>> FillConceptionAsync()
    {
        return await CommDataMethod<Conception>.GetDataOnDbSetAsync();
    }
}

/// <summary>
///     画K线图时，相关数据传递结构类
/// </summary>
/// <param name="StockInfo"></param>
/// <param name="Candles"></param>
/// <param name="Financials"></param>
/// <param name="MinuteDatas"></param>
/// <returns></returns>
public class KlineData
{
    public StockInfo StockInfo { get; set; }//股票基础信息
    public IList<Daily> Dailies { get; set; }//日交易记录
    public IList<DynamicFinancialIndex> Financials { get; set; }//季度主要财务指标
    public IList<MinuteData> MinuteDatas { get; set; }//当日分钟数据

    public void Dispose()
    {
        StockInfo = null;
        Dailies.Dispose();
        Financials.Dispose();
        MinuteDatas.Dispose();
    }
}